/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "mokoko_music_panel.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <libgen.h>

#include <Edje.h>
#include <Edje_Edit.h>
#include <etk/Etk.h>
#include <etk/etk_container.h>

#include "collections.h"
#include "config.h"
#include "playback.h"
#include "debug.h"

static Etk_Widget  *songs_list_tree;
static Collections *collection;

/**
 * Initial the state of some objects on the Play panel when launch Mokoko
 */
void _init_objects_state(Evas_Object* panel) {
        edje_edit_program_run(panel, "hide_volume_bar");
        edje_edit_program_run(panel, "hide_volume_button");
        edje_edit_program_run(panel, "hide_songs_list");
}

/**
 * Append the song title into the Tree
 */
void _append_song_into_tree(Etk_Widget* tree, Etk_Tree_Col* col,const char* song) {
        char buf[1024];
        snprintf(buf, sizeof(buf), "<b><font_size=30>%s</></b>",song);
        etk_tree_row_append(ETK_TREE(tree), NULL, col, buf, NULL);
        etk_tree_thaw(ETK_TREE(tree));
}

/**
 * Create a tree which contains song title. Set the status of the tree and return it
 */
Etk_Widget * _get_tree(Evas * evas) {
        Etk_Widget *tree  = etk_tree_new();
        etk_scrolled_view_policy_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), ETK_POLICY_HIDE, ETK_POLICY_HIDE);
        etk_scrolled_view_dragable_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), ETK_TRUE);
        etk_scrolled_view_drag_damping_set(etk_tree_scrolled_view_get(ETK_TREE(tree)), MOKOKO_DAMPING);

        etk_tree_mode_set(ETK_TREE(tree), ETK_TREE_MODE_LIST);
        etk_tree_multiple_select_set(ETK_TREE(tree), ETK_FALSE);
        etk_tree_rows_height_set (ETK_TREE(tree), 50);

        Etk_Tree_Col *col = etk_tree_col_new(ETK_TREE(tree), NULL, 380, 0.0);
        etk_tree_col_model_add(col, etk_tree_model_text_new());
        etk_tree_headers_visible_set(ETK_TREE(tree), 0);
        etk_tree_build(ETK_TREE(tree));

        return tree;
}

/**
 * Callback : call it when User select a row of songs list
 */
Etk_Bool _cb_list_selected(Etk_Tree *tree, Etk_Tree_Row *selected_row,const char *emission, void* data) {
        debug("Tree selected\n");
        int N_th       = -1;
        int is_shuffle = 0;
        Etk_Tree_Row *now        = NULL;
        Evas_Object  *after_cast = NULL;

        now = etk_tree_first_row_get(tree);

        while( now != NULL) { // User select the <N_th> song
                if(now == selected_row)
                        now = NULL;
                now = etk_tree_row_next_get(now);
                N_th++;
        }

        is_shuffle = mokoko_media_playlist_shuffle_get();
        mokoko_media_playlist_play(0, is_shuffle, N_th);

        // Change the status of music_button_play to <Pause>
        // because Mokoko is playing music
        after_cast = (Evas_Object *) data;
        if(after_cast) {
                edje_edit_program_run(after_cast,"show_button_pause");
        }
        else {
                debug("play panel is null!!\n");
                return ETK_FALSE;
        }

        return ETK_TRUE;
}

/**
 * Callback: call it when User click now_playing_title
 */
void _cb_show_hide_list(void* data, Evas_Object* object, const char* emission, const char* source) {

        char *state_playing_list =  (char *) edje_edit_part_selected_state_get(object,"songs_list_panel");
        debug("click title, state of songs list is %s\n", state_playing_list);

        if(strcmp("default 0.00", state_playing_list) == 0) {
            edje_edit_program_run(object, "hide_songs_list");
        }else if (strcmp("hide 0.00", state_playing_list) == 0) {
            edje_edit_program_run(object, "show_songs_list");
        }else {
                debug("Unknown state of Playing List\n");
        }
}

/**
 * Callback: call it when User click button_volume
 */
void _cb_show_hide_volume(void* data, Evas_Object* object, const char* emission, const char* source) {

        char *state_volume_bar = (char *)edje_edit_part_selected_state_get(object, "volume_bar");

        if(strcmp("default 0.00", state_volume_bar) == 0) {
            edje_edit_program_run(object, "hide_volume_bar");
            edje_edit_program_run(object, "hide_volume_button");

        }else if (strcmp("hide 0.00", state_volume_bar) == 0) {
            edje_edit_program_run(object, "show_volume_bar");
            edje_edit_program_run(object, "show_volume_button");

        }else {
                debug("Unknown state of volume_bar\n");
        }
}

/**
 * Callback: call it when User drag the Volume Bar.
 */
void _cb_volume_change(void* data, Evas_Object* object, const char* emission, const char* source) {

        double x = 0, y = 0;
        int volume = 100;

        edje_object_part_drag_value_get(object, "volume_button", &x, &y);
        debug("drag value is :%f, %f\n", x, y);

        volume = 100 - (int)(100*y);
        mokoko_media_volume_set(volume);
}

/**
 * Callback: call it when User click button_play_next
 */
void _cb_play_next(void* data,Evas_Object* object, const char* emission, const char* source) {

        debug("Next clicked\n");
        mokoko_media_play_next();
        if (mokoko_media_state_get() == MOKOKO_STATE_READY) {
                edje_edit_program_run(object,"show_button_pause");
        }
}

/**
 * Callback: call it when User click button_play_prev
 */
void _cb_play_prev(void* data,Evas_Object* object, const char* emission, const char* source) {

        debug("Prev clicked\n");
        mokoko_media_play_prev();
        if (mokoko_media_state_get() == MOKOKO_STATE_READY) {
                edje_edit_program_run(object,"show_button_pause");
        }
}

/**
 * Callback: call it when User click Random/Normal mode button.
 * Fixme: We didn't connect it to workable function yet.
 */
void _cb_random_or_normal(void* data,Evas_Object* object, const char* emission, const char* source) {

        debug("Mode clicked\n");
        char *state_button_mode;
        int state_is_default;
        int state_is_random;

        state_button_mode = (char *)edje_edit_part_selected_state_get(object,"button_play_mode");
        debug("state is %s\n",state_button_mode);

        state_is_default  = strcmp("default 0.00", state_button_mode);
        state_is_random   = strcmp("random 0.00", state_button_mode);

        if(state_is_default == 0) {
                debug("Set state to random\n");
                edje_edit_program_run(object,"show_button_random");
                mokoko_media_playlist_shuffle_set(TRUE);

        }else if (state_is_random == 0) {
                debug("Set state to default\n");
                edje_edit_program_run(object,"show_button_normal");
                mokoko_media_playlist_shuffle_set(FALSE);

        }else {
                debug("Something wrong when call random_or_normal");
        }
        set_playlist(collection);
}

/**
 * Callback: call it when User click Play/Pause button.
 *
 * When User click <Play> button, Mokoko start playing music and set button as <Pause>
 * If Mokoko is already playing music, pause it 
 * and set button as <Play> to remind User: You can play music.
 */
void _cb_play_or_pause(void* data,Evas_Object* object, const char* emission, const char* source) {

        debug("Play clicked\n");
        int is_shuffle = 0;

        MokokoState now_state = mokoko_media_state_get();

        if(now_state == MOKOKO_STATE_PAUSED) {
                mokoko_media_resume();
                edje_edit_program_run(object,"show_button_pause");

        }else if(now_state == MOKOKO_STATE_PLAYING) {
                mokoko_media_pause();
                edje_edit_program_run(object,"show_button_play");

        }else if(now_state == MOKOKO_STATE_PIPELINE_NULL ||
                 now_state == MOKOKO_STATE_NULL) {
                // it is the first time Mokoko try to play music.
                // Let's play the first song
                is_shuffle = mokoko_media_playlist_shuffle_get();
                mokoko_media_playlist_play(0, is_shuffle, 0);
                edje_edit_program_run(object,"show_button_pause");

        }else {
                debug("Unhandled state: %d\n", (int)now_state);
        }
}

static Ecore_Event_Handler *event_handler = NULL;

// We can handle the event from "Controller" here. 
static int _on_playback_changed(void *data, int type, void *event) {
        MKK_Event *ev = (MKK_Event *)event;
        debug("Event Type:%d, value is %d\n", ev->type, (int)ev->value);
        if(ev->type == MKK_EVENT_TYPE_ERROR) {
                debug("Error code: %d, error message is \"%s\"\n", (int)ev->value, ev->message);
        }
        return 1;
}

/**
 * Clear playlist and append content from collection to playlist
 * @param collections Collections contain songs what you want to put into playing list
 */
void set_playlist(Collections* collections) {
        Etk_Tree_Col* col = etk_tree_nth_col_get(ETK_TREE(songs_list_tree), 0);
        Song *song, *song_n;
        int is_shuffle = 0;

        etk_tree_clear(ETK_TREE(songs_list_tree));

        is_shuffle = mokoko_media_playlist_shuffle_get();
        if(is_shuffle) {
                list_for_each_entry_safe(song, song_n, &collections->shuffle_list_head, shuffle_list_node) {
                        char* filename = song->file;
                        _append_song_into_tree(songs_list_tree,col,(char*) basename(filename));
                }
        }else {
                list_for_each_entry_safe(song, song_n, &collections->all_songs_head, all_song_node) {
                        char* filename = song->file;
                        _append_song_into_tree(songs_list_tree,col,(char*) basename(filename));
                }
        }        
}

/**
 * Initialize the main Music Playing Panel.
 * @param collections Collections contain songs what are put into playing list by default
 */
int init_music_panel(Collections *collections) {

        Ecore_Evas *ee;
        Evas       *evas;
        char edj_path[1024];
        Etk_Widget *embed;

        collection = collections;

        /* Initial the basic music_panel */
        ee = ecore_evas_software_x11_new(NULL, 0,  0, 0, WIDTH, HEIGHT);
        ecore_evas_title_set(ee, "Mokoko");
        ecore_evas_show(ee);
        evas = ecore_evas_get(ee);

        /* Read in edj file and set size of panel*/
        Evas_Object *player_panel = edje_object_add(evas);
        snprintf(edj_path, sizeof(edj_path), "%s/mokoko.edj", THEME_PATH);
        debug("path is %s\n",edj_path);

        edje_object_file_set(player_panel, edj_path,"mokoko/music_panel");
        evas_object_move(player_panel, 0, 0);
        evas_object_resize(player_panel,WIDTH,HEIGHT);
        evas_object_show(player_panel);

        mokoko_media_collections_set(collection);

        /* Create the songs list and put informations into it */
        songs_list_tree = _get_tree(evas);
        set_playlist(collection);

        /* Embed tree into the Panel */
        embed = etk_embed_new(evas);
        etk_container_add(ETK_CONTAINER(embed), ETK_WIDGET(songs_list_tree));
        etk_widget_show_all(embed);

        Evas_Object *tree_object = etk_embed_object_get(ETK_EMBED(embed));
        edje_object_part_swallow(player_panel, "songs_list_panel", tree_object);
        evas_object_show(tree_object);

        /* Connect signal and callback function */
        etk_signal_connect_by_code(ETK_TREE_ROW_CLICKED_SIGNAL, ETK_OBJECT(songs_list_tree), ETK_CALLBACK(_cb_list_selected), player_panel);

        edje_object_signal_callback_add(player_panel,"playing_title_clicked", "now_playing_title", _cb_show_hide_list, NULL);
        edje_object_signal_callback_add(player_panel,"button_mode_clicked", "button_play_mode", _cb_random_or_normal, NULL);
        edje_object_signal_callback_add(player_panel,"button_speaker_clicked", "button_speaker", _cb_show_hide_volume, NULL);
        edje_object_signal_callback_add(player_panel,"button_play_clicked", "button_music_play", _cb_play_or_pause, NULL);
        edje_object_signal_callback_add(player_panel,"button_next_clicked", "button_music_next", _cb_play_next, NULL);
        edje_object_signal_callback_add(player_panel,"button_prev_clicked", "button_music_prev", _cb_play_prev, NULL);
        edje_object_signal_callback_add(player_panel,"drag,stop","volume_button",_cb_volume_change, NULL);

        event_handler = ecore_event_handler_add(MKK_PLAYBACK_EVENT, _on_playback_changed, NULL);
        _init_objects_state(player_panel);
        return 0;
}

